/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Initial Developer of the Original Code is
*   Nick Kreeger
* Portions created by the Initial Developer are Copyright (C) 2006-2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*   Nick Kreeger <nick.kreeger@park.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */

#import "CHMsgMailSession.h"

#include "msgCore.h"
#include "nsIMsgMessageService.h"
#include "nsMsgUtils.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgMessageService.h"
#include "nsMsgUtils.h"
#include "nsIURI.h"
#include "nsXPIDLString.h"
#include "nsIMsgAccountManager.h"
#include "nsIChromeRegistry.h"
#include "nsIDirectoryService.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsReadableUtils.h"

NS_IMPL_THREADSAFE_ADDREF(CHMsgMailSession)
NS_IMPL_THREADSAFE_RELEASE(CHMsgMailSession)
NS_INTERFACE_MAP_BEGIN(CHMsgMailSession)
NS_INTERFACE_MAP_ENTRY(nsIMsgMailSession)
NS_INTERFACE_MAP_ENTRY(nsIFolderListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMsgMailSession)
NS_INTERFACE_MAP_END_THREADSAFE

CHMsgMailSession::CHMsgMailSession()
{
  NS_NewISupportsArray(getter_AddRefs(mWindows));
}

CHMsgMailSession::~CHMsgMailSession()
{
}

nsresult 
CHMsgMailSession::Init()
{
  return NS_OK;
}

#pragma mark -

NS_IMETHODIMP 
CHMsgMailSession::Shutdown()
{
  return NS_OK;
}

NS_IMETHODIMP
CHMsgMailSession::AddFolderListener(nsIFolderListener* listener, folderListenerNotifyFlagValue notifyFlags)
{
  mListeners.AppendObject(listener);
  mListenerNotifyFlags.AppendElement(notifyFlags);
  return NS_OK;
}

NS_IMETHODIMP
CHMsgMailSession::RemoveFolderListener(nsIFolderListener* listener)
{
  PRInt32 index = mListeners.IndexOf(listener);
  NS_ASSERTION(index >= 0, "removing non-existent listener");
  if (index >= 0)
  {
    mListenerNotifyFlags.RemoveElementAt(index);
    mListeners.RemoveObjectAt(index);
  }
  return NS_OK;
}

NS_IMETHODIMP
CHMsgMailSession::GetTopmostMsgWindow(nsIMsgWindow** aTopmostMsgWindow)
{
  nsresult rv;
  if (!aTopmostMsgWindow)
    return NS_ERROR_INVALID_POINTER;
  
  *aTopmostMsgWindow = nsnull;
  
  if (mWindows)
  {
    PRUint32 count;
    rv = mWindows->Count(&count);
    NS_ENSURE_SUCCESS(rv, rv);
    
    nsCOMPtr<nsIMsgWindow> msgWindow;

    if (count == 1)
    {
      msgWindow = do_QueryElementAt(mWindows, 0, &rv);
      NS_ENSURE_SUCCESS(rv, rv);
      NS_IF_ADDREF(*aTopmostMsgWindow = msgWindow);
    }
    else if (count > 1)
    {
      for (PRUint32 i = 0; i < count; i++)
      {
        /*
        nsCOMPtr<nsIMsgWindow> openWindow = getter_AddRefs((nsIMsgWindow*)mWindows->ElementAt(i));
        nsCOMPtr<nsIDOMWindowInternal> internalDOM;
        openWindow->GetWindow(
                              */
      }
    }
  }
  
  return (*aTopmostMsgWindow) ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP
CHMsgMailSession::AddMsgWindow(nsIMsgWindow* msgWindow)
{
  mWindows->AppendElement(msgWindow);
  return NS_OK;
}

NS_IMETHODIMP
CHMsgMailSession::RemoveMsgWindow(nsIMsgWindow* msgWindow)
{
  mWindows->RemoveElement(msgWindow);
  PRUint32 count = 0;
  mWindows->Count(&count);
  if (count == 0)
  {
    nsresult rv;
    nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);
    accountManager->CleanupOnExit();
  }
  
  return NS_OK;
}

NS_IMETHODIMP
CHMsgMailSession::GetMsgWindowsArray(nsISupportsArray** aMsgWindowsArray)
{
  if(!aMsgWindowsArray)
    return NS_ERROR_NULL_POINTER;
  
  *aMsgWindowsArray = mWindows;
  NS_IF_ADDREF(*aMsgWindowsArray);
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::IsFolderOpenInWindow(nsIMsgFolder* folder, PRBool* aResult)
{
  if (!aResult)
    return NS_ERROR_NULL_POINTER;
  
  *aResult = PR_FALSE;
  PRUint32 count;
  nsresult rv = mWindows->Count(&count);
  NS_ENSURE_SUCCESS(rv, rv);
  
  if (mWindows)
  {
    for (PRUint32 i = 0; i < count; i++)
    {
      nsCOMPtr<nsIMsgWindow> openWindow = getter_AddRefs((nsIMsgWindow*)mWindows->ElementAt(i));
      nsCOMPtr<nsIMsgFolder> openFolder;
      if (openWindow)
        openWindow->GetOpenFolder(getter_AddRefs(openFolder));
      if (folder == openFolder.get())
      {
        *aResult = PR_TRUE;
        break;
      }
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::ConvertMsgURIToMsgURL(const char* aURI, nsIMsgWindow* aMsgWindow, char** aURL)
{
  if ((!aURI) || (!aURL))
    return NS_ERROR_NULL_POINTER;
  
  // convert the rdf msg uri into a url that represents the message...
  nsresult rv;
  nsCOMPtr <nsIMsgMessageService> msgService;
  rv = GetMessageServiceFromURI(aURI, getter_AddRefs(msgService));
  NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER);
  
  nsCOMPtr<nsIURI> tURI;
  rv = msgService->GetUrlForUri(aURI, getter_AddRefs(tURI), aMsgWindow);
  NS_ENSURE_SUCCESS(rv, NS_ERROR_NULL_POINTER);
  
  nsCAutoString urlString;
  if (NS_SUCCEEDED(tURI->GetSpec(urlString)))
  {
    *aURL = ToNewCString(urlString);
    if (!(aURL))
      return NS_ERROR_NULL_POINTER;
  }
  
  return rv;
}

NS_IMETHODIMP 
CHMsgMailSession::GetDataFilesDir(const char* dirName, nsIFile** dataFilesDir)
{
  NS_ENSURE_ARG_POINTER(dataFilesDir);
  
  nsresult rv;
  nsCOMPtr<nsIProperties> directoryService = 
    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv,rv);
  
  nsCOMPtr<nsIFile> defaultsDir;
  rv = directoryService->Get(NS_APP_DEFAULTS_50_DIR, 
                             NS_GET_IID(nsIFile), 
                             getter_AddRefs(defaultsDir));
  NS_ENSURE_SUCCESS(rv,rv);
  
  rv = defaultsDir->AppendNative(nsDependentCString(dirName));
  if (NS_SUCCEEDED(rv))
    rv = GetSelectedLocaleDataDir(defaultsDir);
  
  NS_IF_ADDREF(*dataFilesDir = defaultsDir);
  
  return rv;
}

nsresult
CHMsgMailSession::GetSelectedLocaleDataDir(nsIFile *defaultsDir)
{                                                                               
  NS_ENSURE_ARG_POINTER(defaultsDir);                                     
  
  nsresult rv;                                                                
  PRBool baseDirExists = PR_FALSE;                                            
  rv = defaultsDir->Exists(&baseDirExists);                               
  NS_ENSURE_SUCCESS(rv,rv);                                                   
  
  if (baseDirExists)
  {                                                        
    nsCOMPtr<nsIXULChromeRegistry> packageRegistry = do_GetService("@mozilla.org/chrome/chrome-registry;1", &rv);
    if (NS_SUCCEEDED(rv)) 
    {                                                 
      nsCAutoString localeName;                                           
      rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global-region"), localeName);
      
      if (NS_SUCCEEDED(rv) && !localeName.IsEmpty()) 
      {
        PRBool localeDirExists = PR_FALSE;                              
        nsCOMPtr<nsIFile> localeDataDir;                                
        
        rv = defaultsDir->Clone(getter_AddRefs(localeDataDir));     
        NS_ENSURE_SUCCESS(rv,rv);                                       
        
        rv = localeDataDir->AppendNative(localeName);
        NS_ENSURE_SUCCESS(rv,rv);                                       
        
        rv = localeDataDir->Exists(&localeDirExists);                   
        NS_ENSURE_SUCCESS(rv,rv);                                       
        
        // use locale provider instead 
        if (localeDirExists) 
        {                                                           
          rv = defaultsDir->AppendNative(localeName);
          NS_ENSURE_SUCCESS(rv,rv);                                   
        }                                                               
      }                                                                   
    }                                                                       
  }    
  
  return NS_OK;                                                               
} 

#pragma mark -

NS_IMETHODIMP 
CHMsgMailSession::OnItemAdded(nsIRDFResource* parentItem, nsISupports* item)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::added)
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener) 
        return NS_ERROR_FAILURE;
      
      listener->OnItemAdded(parentItem, item);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemRemoved(nsIRDFResource* parentItem, nsISupports* item)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::removed)
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener) 
        return NS_ERROR_FAILURE;
      
      listener->OnItemRemoved(parentItem, item);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemPropertyChanged(nsIRDFResource* item, nsIAtom* property, const char* oldValue, const char* newValue)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::propertyChanged)
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener) 
        return NS_ERROR_FAILURE;
      
      listener->OnItemPropertyChanged(item, property, oldValue, newValue);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemIntPropertyChanged(nsIRDFResource* item, nsIAtom* property, PRInt32 oldValue, PRInt32 newValue)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::intPropertyChanged) 
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener)
        return NS_ERROR_FAILURE;
      
      listener->OnItemIntPropertyChanged(item, property, oldValue, newValue);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemBoolPropertyChanged(nsIRDFResource* item, nsIAtom* property, PRBool oldValue, PRBool newValue)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::boolPropertyChanged)
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener) 
        return NS_ERROR_FAILURE;
      
      listener->OnItemBoolPropertyChanged(item, property, oldValue, newValue);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemUnicharPropertyChanged(nsIRDFResource* item,
                                               nsIAtom* property,
                                               const PRUnichar* oldValue,
                                               const PRUnichar* newValue)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::unicharPropertyChanged) 
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener) 
        return NS_ERROR_FAILURE;
      
      listener->OnItemUnicharPropertyChanged(item, property, oldValue, newValue);
    }
  }

  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemPropertyFlagChanged(nsIMsgDBHdr* item, nsIAtom* property, PRUint32 oldFlag, PRUint32 newFlag)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::propertyFlagChanged)
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      NS_ASSERTION(listener, "listener is null");
      if (!listener)
        return NS_ERROR_FAILURE;
      
      listener->OnItemPropertyFlagChanged(item, property, oldFlag, newFlag);
    }
  }
  
  return NS_OK;
}

NS_IMETHODIMP 
CHMsgMailSession::OnItemEvent(nsIMsgFolder* aFolder, nsIAtom* aEvent)
{
  PRInt32 count = mListeners.Count();
  for (PRInt32 i = 0; i < count; i++)
  {
    if (mListenerNotifyFlags[i] & nsIFolderListener::event) 
    {
      nsCOMPtr<nsIFolderListener> listener = mListeners[i];
      if (listener)
        listener->OnItemEvent(aFolder, aEvent);
    }
  }
  
  return NS_OK;
}
